/*
 * Copyright (c) 2018-2999 深圳市阿毛科技有限公司 All rights reserved.
 *
 * https://www.lamyz.com/
 *
 * 未经允许，不可做商业用途！
 *
 * 版权所有，侵权必究！
 */

package com.lam.mall.api.controller;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.google.common.collect.Lists;
import com.lam.common.base.domain.Result;
import com.lam.common.constant.CommonConstant;
import com.lam.common.constant.MallStateConstant;
import com.lam.common.context.TokenUtils;
import com.lam.common.utils.NumberUtil;
import com.lam.framework.operLog.annotation.Log;
import com.lam.mall.app.param.ChangeShopCartParam;
import com.lam.mall.app.param.ShopCartParam;
import com.lam.mall.app.vo.ShopCartAmountVo;
import com.lam.mall.app.vo.ShopCartExpiryItemVo;
import com.lam.mall.app.vo.ShopCartItemDiscountVo;
import com.lam.mall.app.vo.ShopCartItemVo;
import com.lam.mall.app.vo.ShopCartVo;
import com.lam.mall.common.event.ShopCartEvent;
import com.lam.mall.entity.Basket;
import com.lam.mall.entity.ProdSku;
import com.lam.mall.entity.Product;
import com.lam.mall.service.BasketService;
import com.lam.mall.service.ProdSkuService;
import com.lam.mall.service.ProductService;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;

/**
 */
@RestController
@RequestMapping("/${frontPath}/shopCart")
@Log(title = "购物车接口")
public class ShopCartApiController {

	@Autowired
    private BasketService basketService;
	@Autowired
    private ProductService productService;
	@Autowired
    private ProdSkuService prodSkuService;
	@Autowired
    private ApplicationContext applicationContext;

    /**
     * 获取用户购物车信息
     * 参数为用户选中的活动项数组,以购物车id为key
     * @param basketIdShopCartParamMap 购物车参数对象列表
     * @return
     */
    @PostMapping("/info")
    @Log(oper = "获取用户购物车信息")
    public Result info(@RequestBody Map<String, ShopCartParam> basketIdShopCartParamMap) {
        String userId = TokenUtils.getLoginUserid();

        // 更新购物车信息，
        if (MapUtil.isNotEmpty(basketIdShopCartParamMap)) {
            basketService.updateBasketByShopCartParam(userId, basketIdShopCartParamMap);
        }

        // 拿到购物车的所有item
        List<ShopCartItemVo> shopCartItems = basketService.getShopCartItems(userId);
        return Result.ok(basketService.getShopCarts(shopCartItems));

    }

    @DeleteMapping("/deleteItem")
    @Log(oper = "删除用户购物车物品")
    public Result deleteItem(@RequestBody List<String> basketIds) {
        String userId = TokenUtils.getLoginUserid();
        basketService.deleteShopCartItemsByBasketIds(userId, basketIds);
        return Result.ok();
    }

    @DeleteMapping("/deleteAll")
    @Log(oper = "清空用户购物车所有物品")
    public Result deleteAll() {
        String userId = TokenUtils.getLoginUserid();
        basketService.deleteAllShopCartItems(userId);
        return Result.ok("删除成功");
    }

    /**
     * 通过商品id(prodId)、skuId、店铺Id(shopId),添加/修改用户购物车商品，并传入改变的商品个数(count)，" +
            "当count为正值时，增加商品数量，当count为负值时，将减去商品的数量，当最终count值小于0时，会将商品从购物车里面删除
     * @param param
     * @return
     */
    @PostMapping("/changeItem")
    @Log(oper = "添加、修改用户购物车物品")
    public Result addItem(@Valid @RequestBody ChangeShopCartParam param) {

        if (param.getCount() == 0) {
            return Result.fail("请输入更改数量");
        }
        
        String userId = TokenUtils.getLoginUserid();
        List<ShopCartItemVo> shopCartItems = basketService.getShopCartItems(userId);
        Product prodCache = productService.getSampleProdByIdCache(param.getProdId());
        ProdSku skuCache = prodSkuService.getBySkuIdCache(param.getSkuId());

        // 当商品状态不正常时，不能添加到购物车
        if (!NumberUtil.eq(prodCache.getStatus(), MallStateConstant.STATUS_ONLINE) 
        		|| !NumberUtil.eq(skuCache.getStatus(), CommonConstant.STATUS_NORMAL_1)) {
            return Result.fail("当前商品已下架");
        }
        
        for (ShopCartItemVo shopCartItemVo : shopCartItems) {
            if (Objects.equals(param.getSkuId(), shopCartItemVo.getSkuId())) {
                Basket basket = new Basket();
                basket.setUserId(userId);
                basket.setBasketCount(param.getCount() + shopCartItemVo.getProdCount());
                basket.setId(shopCartItemVo.getBasketId());

                // 防止购物车变成负数
                if (basket.getBasketCount() <= 0) {
                    basketService.deleteShopCartItemsByBasketIds(userId, Collections.singletonList(basket.getId()));
                    return Result.ok();
                }

                // 当sku实际库存不足时，不能添加到购物车
                if (skuCache.getStocks() < basket.getBasketCount() && shopCartItemVo.getProdCount() > 0) {
                    return Result.fail("库存不足");
                }
                basketService.updateShopCartItem(basket);
                return Result.ok();
            }
        }
        
        // 防止购物车已被删除的情况下,添加了负数的商品
        if (param.getCount() < 0) {
            return Result.fail("商品已从购物车移除");
        }
        // 当sku实际库存不足时，不能添加到购物车
        if (skuCache.getStocks() < param.getCount()) {
            return Result.fail("库存不足");
        }
        // 所有都正常时
        basketService.addShopCartItem(param,userId);
        return Result.ok("添加成功");
    }

    @GetMapping("/prodCount")
    @Log(oper = "获取购物车商品数量")
    public Result prodCount() {
        String userId = TokenUtils.getLoginUserid();
        List<ShopCartItemVo> shopCartItems = basketService.getShopCartItems(userId);
        if (CollectionUtil.isEmpty(shopCartItems)) {
            return Result.ok(0);
        }
        Integer totalCount = shopCartItems.stream().map(ShopCartItemVo::getProdCount).reduce(0, Integer::sum);
        return Result.ok(totalCount);
    }

    @GetMapping("/expiryProdList")
    @Log(oper = "获取购物车失效商品信息")
    public Result expiryProdList() {
        String userId = TokenUtils.getLoginUserid();
        List<ShopCartItemVo> shopCartItems = basketService.getShopCartExpiryItems(userId);
        //根据店铺ID划分item
        Map<String, List<ShopCartItemVo>> shopCartItemVoMap = shopCartItems.stream().collect(Collectors.groupingBy(ShopCartItemVo::getShopId));

        // 返回一个店铺对应的所有信息
        List<ShopCartExpiryItemVo> shopcartExpiryitems = Lists.newArrayList();

        for (String key : shopCartItemVoMap.keySet()) {
            ShopCartExpiryItemVo shopCartExpiryItemVo = new ShopCartExpiryItemVo();
            shopCartExpiryItemVo.setShopId(key);
            List<ShopCartItemVo> shopCartItemVos = Lists.newArrayList();
            for (ShopCartItemVo tempShopCartItemVo : shopCartItemVoMap.get(key)) {
                shopCartExpiryItemVo.setShopName(tempShopCartItemVo.getShopName());
                shopCartItemVos.add(tempShopCartItemVo);
            }
            shopCartExpiryItemVo.setShopCartItemVoList(shopCartItemVos);
            shopcartExpiryitems.add(shopCartExpiryItemVo);
        }

        return Result.ok(shopcartExpiryitems);
    }

    @DeleteMapping("/cleanExpiryProdList")
    @Log(oper = "清空用户失效商品")
    public Result cleanExpiryProdList() {
        String userId = TokenUtils.getLoginUserid();
        basketService.cleanExpiryProdList(userId);
        return Result.ok();
    }

    /**
     * 获取选中购物项总计、选中的商品数量,参数为购物车id数组
     * @param basketIds
     * @return
     */
    @PostMapping("/totalPay")
    @Log(oper = "获取选中购物项总计、选中的商品数量")
    public Result getTotalPay(@RequestBody List<String> basketIds) {

        // 拿到购物车的所有item
        List<ShopCartItemVo> dbShopCartItems = basketService.getShopCartItems(TokenUtils.getLoginUserid());

        List<ShopCartItemVo> chooseShopCartItems = dbShopCartItems.stream()
                                                        .filter(shopCartItemVo -> {
                                                            for (String basketId : basketIds) {
                                                                if (Objects.equals(basketId,shopCartItemVo.getBasketId())) {
                                                                    return  true;
                                                                }
                                                            }
                                                            return false;
                                                        }).collect(Collectors.toList());

        // 根据店铺ID划分item
        Map<String, List<ShopCartItemVo>> shopCartMap = chooseShopCartItems.stream().collect(Collectors.groupingBy(ShopCartItemVo::getShopId));

        BigDecimal total = BigDecimal.ZERO;
        int count = 0;
        BigDecimal reduce = BigDecimal.ZERO;
        for (String shopId : shopCartMap.keySet()) {
            //获取店铺的所有商品项
            List<ShopCartItemVo> shopCartItemVoList = shopCartMap.get(shopId);
            // 构建每个店铺的购物车信息
            ShopCartVo shopCart = new ShopCartVo();
            shopCart.setShopId(shopId);

            applicationContext.publishEvent(new ShopCartEvent(shopCart, shopCartItemVoList));

            List<ShopCartItemDiscountVo> shopCartItemDiscounts = shopCart.getShopCartItemDiscounts();

            for (ShopCartItemDiscountVo shopCartItemDiscount : shopCartItemDiscounts) {
                List<ShopCartItemVo> shopCartItems = shopCartItemDiscount.getShopCartItems();

                for (ShopCartItemVo shopCartItem : shopCartItems) {
                    count = shopCartItem.getProdCount() + count;
                    total = NumberUtil.add(shopCartItem.getProductTotalAmount(), total);
                }
            }
        }
        ShopCartAmountVo shopCartAmountVo = new ShopCartAmountVo();
        shopCartAmountVo.setCount(count);
        shopCartAmountVo.setTotalMoney(total);
        shopCartAmountVo.setSubtractMoney(reduce);
        shopCartAmountVo.setFinalMoney(NumberUtil.subtract(shopCartAmountVo.getTotalMoney(), shopCartAmountVo.getSubtractMoney()));

        return Result.ok(shopCartAmountVo);
    }

}
